package cn.xiaosiyuan.javaagenthelloworld;

import javassist.*;

import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;

public class JavaAgentHelloWorld {

    public static void premain (String agentOps, Instrumentation Instrumentation){
        System.out.println("====premain 方法执行");

        final ClassPool pool = new ClassPool();
        pool.appendSystemPath();

//        添加类装载过滤器
        Instrumentation.addTransformer(new ClassFileTransformer() {
            /*
            这里监控的是cn/xiaosiyuan/javaagenthelloworld/UserService类中的sayHello方法
            * */
            @Override
            public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
                if (!"cn/xiaosiyuan/javaagenthelloworld/UserService".equals(className)){
                    return null;
                }
                try {
                    CtClass ctClass = pool.get("cn.xiaosiyuan.javaagenthelloworld.UserService");
                    CtMethod sayHello = ctClass.getDeclaredMethod("sayHello");
                    sayHello.insertBefore("System.out.println(System.currentTimeMillis());");

//                    1.复制方法
                    CtMethod copy = CtNewMethod.copy(sayHello, ctClass, null);
                    copy.setName("sayHello$agent");
                    ctClass.addMethod(copy);
//                    2.改变原有方法
                    sayHello.setBody("{ long begin = System.currentTimeMillis();\n" +
                            "                    sayHello$agent($1);\n" +
                            "                    System.out.println(System.currentTimeMillis() - begin); }");
                    return ctClass.toBytecode();
                } catch (NotFoundException e) {
                    e.printStackTrace();
                } catch (CannotCompileException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return null;
            }
        });
    }

    public static void main(String[] args) {

    }
}
